package com.zhiche.lisa.bms.service.charge.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.zhiche.lisa.bms.dao.mapper.charge.ChargeOffRuleMapper;
import com.zhiche.lisa.bms.dao.model.bill.Bill;
import com.zhiche.lisa.bms.dao.model.bill.BillDetail;
import com.zhiche.lisa.bms.dao.model.charge.ChargeOffRule;
import com.zhiche.lisa.bms.dao.model.fee.FeePayable;
import com.zhiche.lisa.bms.pojo.dto.util.mdm.TransportationTypeDTO;
import com.zhiche.lisa.bms.service.bill.BillDetailService;
import com.zhiche.lisa.bms.service.bill.BillService;
import com.zhiche.lisa.bms.service.charge.ChargeOffRuleService;
import com.zhiche.lisa.bms.service.fee.FeePayableService;
import com.zhiche.lisa.bms.service.utils.MdmUtil;
import com.zhiche.lisa.bms.service.utils.common.AccountBindUtil;
import com.zhiche.lisa.core.supports.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 出账规则 服务实现类
 * </p>
 *
 * @author liuanshun
 * @since 2018-11-02
 */
@Service
@Slf4j
public class ChargeOffRuleServiceImpl extends ServiceImpl<ChargeOffRuleMapper, ChargeOffRule> implements ChargeOffRuleService {
    @Autowired
    private FeePayableService feePayableService;
    @Autowired
    private BillService billService;
    @Autowired
    private BillDetailService billDetailService;
    @Autowired
    private MdmUtil mdmUtil;

    private EntityWrapper<ChargeOffRule> bindChargeOffRuleWrapper(Map<String, Object> condition) {
        EntityWrapper<ChargeOffRule> entityWrapper = new EntityWrapper<ChargeOffRule>();
        if (!CollectionUtils.isEmpty(condition)) {
            /*
             * 绑定结果不为空的条件
             */
            entityWrapper.orderBy("gmt_create desc, id desc");
            for (Map.Entry<String, Object> item :
                    condition.entrySet()) {
                if (!StringUtils.isEmpty(item.getValue())) {
                    if ("id".equals(item.getKey())) {
                        entityWrapper.eq("id", item.getValue());
                    }
                    if ("transTypeId".equals(item.getKey())) {
                        entityWrapper.eq("trans_type_id", item.getValue());
                    }
                    if ("fleetId".equals(item.getKey())) {
                        entityWrapper.eq("fleet_id", item.getValue());
                    }
                    if ("fleetIds".equals(item.getKey())) {
                        entityWrapper.in("fleet_id", JSONArray.parseArray(JSONObject.toJSONString(item.getValue())));
                    }
                    if ("fleetName".equals(item.getKey())) {
                        entityWrapper.like("fleet_name", (String) item.getValue());
                    }
                    if ("status".equals(item.getKey())) {
                        entityWrapper.eq("status", item.getValue());
                    }
                    if ("payDays".equals(item.getKey())) {
                        entityWrapper.eq("pay_days", item.getValue());
                    }
                    if ("isStart".equals(item.getKey())) {
                        entityWrapper.eq("is_start", item.getValue());
                    }
                    if ("geEffectiveDate".equals(item.getKey())) {
                        entityWrapper.ge("effective_date", item.getValue());
                    }
                    if ("leEffectiveDate".equals(item.getKey())) {
                        entityWrapper.le("effective_date", item.getValue());
                    }
                    if ("geInvalidDate".equals(item.getKey())) {
                        entityWrapper.ge("invalid_date", item.getValue());
                    }
                    if ("leInvalidDate".equals(item.getKey())) {
                        entityWrapper.le("invalid_date", item.getValue());
                    }
                    if ("validityDate".equals(item.getKey())) {
                        entityWrapper.le("effective_date", item.getValue());
                        entityWrapper.ge("invalid_date", item.getValue());
                    }
                }
            }
            //有效期存在的期间判断，增加索引在s和e之间生效的数据
            if (Objects.nonNull(condition.get("validityDateS")) && Objects.nonNull(condition.get("validityDateE"))) {
                Date validityDateS = (Date) condition.get("validityDateS");
                Date validityDateE = (Date) condition.get("validityDateE");
                entityWrapper.andNew();
                entityWrapper.ge("invalid_date", validityDateS);
                entityWrapper.or();
                entityWrapper.le("effective_date", validityDateE);
            }
        }
        return entityWrapper;
    }

    /**
     * 获取出账规则列表
     *
     * @param condition
     * @return
     */
    @Override
    public List<ChargeOffRule> selectChargeOffRuleList(Map<String, Object> condition) {
        EntityWrapper<ChargeOffRule> chargeOffRuleEntityWrapper = this.bindChargeOffRuleWrapper(condition);
        return this.selectList(chargeOffRuleEntityWrapper);
    }

    /**
     * 获取出账规则分页信息
     *
     * @param pageParam
     * @return
     */
    @Override
    public Page<ChargeOffRule> selectChargeOffRulePage(Page<ChargeOffRule> pageParam) {
        EntityWrapper<ChargeOffRule> chargeOffRuleEntityWrapper = this.bindChargeOffRuleWrapper(pageParam.getCondition());
        return this.selectPage(pageParam.setCondition(new HashMap<>()), chargeOffRuleEntityWrapper);
    }

    /**
     * 新增单条出账规则
     *
     * @param addChargeOffRule
     * @return
     */
    @Override
    public ChargeOffRule insertChargeOffRule(ChargeOffRule addChargeOffRule) {
        try {
            if (addChargeOffRule == null || addChargeOffRule.getFleetId() == null) {
                throw new BaseException("请选择车队");
            }
            if (this.checkOffRuleFleetRepeat(addChargeOffRule)) {
                throw new BaseException("该车队已存在出账规则");
            }
            addChargeOffRule.setGmtCreate(new Date());
            if (addChargeOffRule.getIsStart() == null) {
                addChargeOffRule.setIsStart(1);
            }
            insert(addChargeOffRule);
        } catch (BaseException e) {
            log.error("ChargeOffRuleServiceImpl.insertChargeOffRule error: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("ChargeOffRuleServiceImpl.insertChargeOffRule error: {}", e.getMessage());
            throw new BaseException("新增出账规则失败");
        }
        return addChargeOffRule;
    }

    /**
     * 检查出账规则中是否存在对应车队结果
     *
     * @param addChargeOffRule
     * @return
     */
    private boolean checkOffRuleFleetRepeat(ChargeOffRule addChargeOffRule) {
        if (addChargeOffRule.getFleetId() != null) {
            Map<String, Object> condition = new HashMap<>();
            if (Objects.nonNull(addChargeOffRule.getEffectiveDate())) {
                condition.put("validityDateS", addChargeOffRule.getEffectiveDate());
            }
            if (Objects.nonNull(addChargeOffRule.getInvalidDate())) {
                condition.put("validityDateE", addChargeOffRule.getInvalidDate());
            }
            // ChargeOffRule fleetEqChargeOffRule = this.selectChargeOffRuleByFleetId(addChargeOffRule.getFleetId(), condition);
            // if (fleetEqChargeOffRule != null) {
            // 	if (!Objects.deepEquals(fleetEqChargeOffRule.getId(), addChargeOffRule.getId())) {
            // 		return true;
            // 	}
            // }
            condition.put("fleetId", addChargeOffRule.getFleetId());
            if (addChargeOffRule.getId() != null) {
                condition.put("notEqId", addChargeOffRule.getId());
            }
            Integer count = baseMapper.checkExistRule(condition);
            if (count != 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据车队寻找对应出账规则
     *
     * @param fleetId
     * @param condition
     * @return
     */
    @Override
    public ChargeOffRule selectChargeOffRuleByFleetId(Long fleetId, Map<String, Object> condition) {
        EntityWrapper<ChargeOffRule> chargeOffRuleEntityWrapper = bindChargeOffRuleWrapper(condition);
        chargeOffRuleEntityWrapper.eq("fleet_id", fleetId);
        return this.selectOne(chargeOffRuleEntityWrapper);
    }


    /**
     * 启用出账规则
     *
     * @param id
     * @return
     */
    @Override
    public ChargeOffRule openChargeOffRule(Long id) {
        ChargeOffRule chargeOffRule = null;
        try {
            chargeOffRule = selectById(id);
            if (Integer.valueOf(1).equals(chargeOffRule.getIsStart())) {
                throw new BaseException("已经是启用状态");
            }
            chargeOffRule.setIsStart(1);
            this.updateChargeOffRule(chargeOffRule);
        } catch (BaseException e) {
            log.error("ChargeOffRuleServiceImpl.openChargeOffRule error: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("ChargeOffRuleServiceImpl.openChargeOffRule error: {}", e.getMessage());
            throw new BaseException("启用失败");
        }
        return chargeOffRule;
    }

    @Override
    public ChargeOffRule closeChargeOffRule(Long id) {
        ChargeOffRule chargeOffRule = null;
        try {
            chargeOffRule = selectById(id);
            if (Integer.valueOf(0).equals(chargeOffRule.getIsStart())) {
                throw new BaseException("已经是禁用状态");
            }
            chargeOffRule.setIsStart(0);
            this.updateChargeOffRule(chargeOffRule);
        } catch (BaseException e) {
            log.error("ChargeOffRuleServiceImpl.chargeOffRule error: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("ChargeOffRuleServiceImpl.chargeOffRule error: {}", e.getMessage());
            throw new BaseException("禁用失败");
        }
        return chargeOffRule;
    }

    /**
     * 获取可以出账的规则
     *
     * @return
     */
    @Override
    public List<ChargeOffRule> getArePayableChargeOffRules() {
        DateTime dateTime = new DateTime();
        EntityWrapper<ChargeOffRule> ew = new EntityWrapper<>();

        ew.orNew().eq("pay_dayss", 0).eq("charge_days", dateTime.dayOfWeek().get());
        ew.le("effective_date", dateTime);
        ew.ge("invalid_date", dateTime);
        ew.eq("is_start", 1);

        ew.orNew().eq("pay_dayss", 1)
                .eq("charge_days", dateTime.dayOfMonth().get());
        ew.le("effective_date", dateTime);
        ew.ge("invalid_date", dateTime);
        ew.eq("is_start", 1);
        return this.selectList(ew);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public ChargeOffRule payable(Long id, ChargeOffRule fullParam, EntityWrapper<FeePayable> feeSourceInitEntity) {
        ChargeOffRule chargeOffRule = null;
        try {
            if (Objects.isNull(fullParam)) {
                if (id != null) {
                    chargeOffRule = selectById(id);
                } else {
                    throw new BaseException("请选定对应规则");
                }
            } else {
                chargeOffRule = fullParam;
            }

            if (Integer.valueOf(0).equals(chargeOffRule.getIsStart())) {
                throw new BaseException("该出账规则为禁用状态");
            }
            if (chargeOffRule.getEffectiveDate() == null || chargeOffRule.getEffectiveDate().getTime() > System.currentTimeMillis()) {
                throw new BaseException("该出账规则不在有效期");
            }
            if (chargeOffRule.getInvalidDate() == null || chargeOffRule.getInvalidDate().getTime() < System.currentTimeMillis()) {
                throw new BaseException("该出账规则已过期");
            }
            /*
             * 绑定查询条件，获取应付账款
             */
            EntityWrapper<FeePayable> ew;
            if (feeSourceInitEntity == null) {
                ew = new EntityWrapper<FeePayable>();
            } else {
                ew = feeSourceInitEntity;
            }
            ew.eq("status", 0);
            ew.ne("actual_amt", 0).and().isNotNull("actual_amt");
            if (chargeOffRule.getFleetId() != null) {
                ew.eq("fleet_id", chargeOffRule.getFleetId());
            }
            if (chargeOffRule.getStatus() != null) {
                if (chargeOffRule.getStatus() == 0) {
                    //已发运
                    ew.eq("load_status", 10);
                } else if (chargeOffRule.getStatus() == 1) {
                    //已运抵
                    ew.eq("load_status", 20);
                }
            }
            if (chargeOffRule.getTransTypeId() != null) {
                List<TransportationTypeDTO> transportTypeByServiceTypeId = mdmUtil.getTransportTypeByServiceTypeId(chargeOffRule.getTransTypeId());
                if (!CollectionUtils.isEmpty(transportTypeByServiceTypeId)) {
                    List<Long> transTypeIds = new ArrayList<>();
                    transportTypeByServiceTypeId.forEach(transportationTypeDTO -> transTypeIds.add(transportationTypeDTO.getId()));
                    ew.in("trans_type_id", transTypeIds);
                }
            }
            List<FeePayable> feePayables = feePayableService.selectListNoTenant(ew);

            /*
             * 转换应付账单和详明数据进行保存
             */
            if (!CollectionUtils.isEmpty(feePayables)) {
                createBillAndDetailByFees(feePayables, "系统");
            } else {
                throw new BaseException("无匹配应付账款信息");
            }
        } catch (BaseException e) {
            log.error("ChargeOffRuleServiceImpl.payable error: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("ChargeOffRuleServiceImpl.payable error: {}", e.getMessage());
            throw new BaseException("生成出账信息失败");
        }
        return chargeOffRule;
    }

    /**
     * 根据账款生成对应账单
     *
     * @param feePayables
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void createBillAndDetailByFees(List<FeePayable> feePayables, String userName) {
        if (!CollectionUtils.isEmpty(feePayables)) {
            Bill bill = new Bill();
            bill.setBillProp(0);
            bill.setBillType("20");
            bill.setBillStatus("10");
            bill.setBillProperty(20);
            bill.setPayerId(feePayables.get(0).getPayerId());
            bill.setPayerName(feePayables.get(0).getPayerName());
            bill.setPayeeId(feePayables.get(0).getFleetId());
            bill.setPayeeName(feePayables.get(0).getFleetName());
            bill.setNum(feePayables.size());
            bill.setOrderDate(new Date());
            bill.setCreateUser(userName);
            new AccountBindUtil<Bill>().bindCreatorAndTenantId(bill, true);
            BigDecimal sumActualAmt = new BigDecimal("0");
            BigDecimal sumDeduct = new BigDecimal("0");
            //计算价格
            for (FeePayable feePayable : feePayables) {
                //不等于null和0
                if (feePayable.getActualAmt() != null && BigDecimal.ZERO.compareTo(feePayable.getActualAmt()) != 0) {
                    sumActualAmt = sumActualAmt.add(feePayable.getActualAmt());
                }
                if (feePayable.getDeduct() != null && BigDecimal.ZERO.compareTo(feePayable.getDeduct()) != 0) {
                    sumDeduct = sumDeduct.add(feePayable.getDeduct());
                }
                // feePayable.setStatus(1);
            }
            bill.setGrossAmt(sumActualAmt);
            bill.setDeductSum(sumDeduct);
            billService.insertBillOne(bill);
            //绑定详明数据
            List<BillDetail> billDetails = new ArrayList<>();
            List<Long> updateFeeIds = new ArrayList<>();
            feePayables.forEach(feePayable -> {
                BillDetail billDetail = new BillDetail();
                billDetail.setBillId(bill.getId());
                billDetail.setFeeId(feePayable.getId());
                billDetails.add(billDetail);
                updateFeeIds.add(feePayable.getId());
            });
            billDetailService.insertBatch(billDetails);
            // feePayableService.updateBatchById(feePayables);
            FeePayable updateFeePayable = new FeePayable();
            updateFeePayable.setStatus(1);
            EntityWrapper<FeePayable> entityWrapper = new EntityWrapper();
            entityWrapper.in("id", updateFeeIds);
            feePayableService.update(updateFeePayable, entityWrapper);
        }
    }

    @Override
    public ChargeOffRule checkPayDays(Long fleetId, String checkType) {
        ChargeOffRule chargeOffRule = new ChargeOffRule();
        if (fleetId != null && !Strings.isNullOrEmpty(checkType)) {
            //获取有效内启用的出账规则
            Map<String, Object> condition = new HashMap<>();
            condition.put("fleetId", fleetId);
            condition.put("isStart", 1);
            condition.put("validityDate", new Date());
            EntityWrapper<ChargeOffRule> chargeOffRuleEntityWrapper = bindChargeOffRuleWrapper(condition);
            chargeOffRule = this.selectOne(chargeOffRuleEntityWrapper);
            if (Objects.nonNull(chargeOffRule)) {
                Calendar cal = Calendar.getInstance();
                int day = cal.get(Calendar.DATE);

                Integer payDays = chargeOffRule.getPayDays();

                if ("createPayApply".equals(checkType)) {
                    if (Objects.deepEquals(new Integer(1), payDays)) {
                        if (day > 20) {
                            //throw new BaseException("该车队不在有效创建账期");
                            return null;
                        }
                    } else if (Objects.deepEquals(new Integer(2), payDays)) {
                        if (day > 25) {
                            //throw new BaseException("该车队不在有效创建账期");
                            return null;
                        }

                    }
                } else if ("payableReconciliation".equals(checkType)) {
                    if (Objects.deepEquals(new Integer(0), payDays)) {
                        if (day > 10) {
                            throw new BaseException("该车队不在有效对账期");
                        }
                    } else if (Objects.deepEquals(new Integer(1), payDays)) {
                        if (day > 15) {
                            throw new BaseException("该车队不在有效对账期");
                        }
                    } else if (Objects.deepEquals(new Integer(2), payDays)) {
                        if (day > 20) {
                            throw new BaseException("该车队不在有效对账期");
                        }
                    }
                }
            }
        }
        return chargeOffRule;
    }

    /**
     * 根据车队集合和有效期判断是否存在出账规则
     *
     * @param fleetIdList
     * @param effectDate
     * @param invalidDate
     * @return
     */
    @Override
    public Integer getExistCount(List<String> fleetIdList, Date effectDate, Date invalidDate) {
        if (!CollectionUtils.isEmpty(fleetIdList) && effectDate != null && invalidDate != null) {
            Map<String, Object> condition = Maps.newHashMap();
            condition.put("validityDateS", new DateTime(effectDate).toString("yyyy-MM-dd"));
            condition.put("validityDateE", new DateTime(invalidDate).toString("yyyy-MM-dd"));
            condition.put("fleetIds", fleetIdList);
            return baseMapper.checkExistRule(condition);
        }
        return null;
    }


    /**
     * 修改单条出账规则
     *
     * @param newChargerOffRule
     * @return
     */
    @Override
    public ChargeOffRule updateChargeOffRule(ChargeOffRule newChargerOffRule) {
        try {
            if (newChargerOffRule == null || newChargerOffRule.getFleetId() == null) {
                throw new BaseException("请选择车队");
            }
            if (this.checkOffRuleFleetRepeat(newChargerOffRule)) {
                throw new BaseException("该车队已存在出账规则");
            }
            updateById(newChargerOffRule);
        } catch (BaseException e) {
            log.error("ChargeOffRuleServiceImpl.updateChargeOffRule error: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("ChargeOffRuleServiceImpl.updateChargeOffRule error: {}", e.getMessage());
            throw new BaseException("修改单条出账规则失败");
        }
        return newChargerOffRule;
    }
}
